This is an R Markdown
Notebook. When you execute code within the notebook, the results appear
beneath the code.
Try executing this chunk by clicking the Run button within
the chunk or by placing your cursor inside it and pressing
Ctrl+Shift+Enter.
##install.packages("dplyr")
##install.packages("jsonlite")
##install.packages("rjson")
##install.packages("ggplot2")
library(conflicted)
library(rjson)
library(dplyr)
library(jsonlite)
library(tidyverse)
library(ggplot2)
Add a new chunk by clicking the Insert Chunk button on the
toolbar or by pressing Ctrl+Alt+I.
When you save the notebook, an HTML file containing the code and
output will be saved alongside it (click the Preview button or
press Ctrl+Shift+K to preview the HTML file).
The preview shows you a rendered HTML copy of the contents of the
editor. Consequently, unlike Knit, Preview does not
run any R code chunks. Instead, the output of the chunk when it was last
run in the editor is displayed.
proyecto stream exitoso en spotify
exploramos datos por última vez antes de ir a lo nuestro
datos pid
primera_columna <- df_data_spotify$X1048588
df_pid <- data.frame(pid = primera_columna)
head(df_pid,10)
datos tracks_uri
df_data_spotify <- read.csv("C:/Users/Edgar/Documents/GitHub/DataMining_and_MachineLearning_EdgarV/data/Proyecto1/sample_submission.csv")
## transformamos las filas restantes en listas
listas_filas <- lapply(1:nrow(df_data_spotify),function(i) as.list(t(df_data_spotify[i,-1])))
##dataframe de listas_filas
df_tracks_uri <- data.frame(track_uri = unlist(listas_filas))
head(df_tracks_uri,2)
exploramos datos por última vez antes de ir a lo nuestro
datos track_uri
head(df_tracks_uri,1000)
una vez obtenidos los valores que necesitamos procedemos a
contarlos
con esto comprobamos que hay 10000 datos de sesión de
streamings
ahora contamos los datos totales de las pistal
df_numero_total_tracks <- df_tracks_uri%>%
select(tracks_uri)%>%
count()
df_numero_total_tracks
realizamos la diferencia para contabilizar el numero real de
pistas
num_real_pistas <- df_numero_total_tracks - df_numero_tracks_repetidos
num_real_pistas
ahora contamos los streamings que tiene el otro dataset
num_streamings <- df_spotify%>%
select(pid)%>%
count()
num_streamings
NA
por lo visto el número de streamings coinciden con los datos del
dataset de las pistas
ahora contamos los datos de las pistas del dataset challenge
primero unimos los dataframes en uno solo
new_df_tracks <- bind_rows(df_tracks, .id = "dataframe_id")
new_df_tracks
ahora contamos el numero de pistas que tiene este dataset
num_tracks <- new_df_tracks%>%
select(track_uri)%>%
count()
num_tracks
revisamos si no hay repetidos
num_tracks <- new_df_tracks%>%
distinct(track_uri)%>%
count()
num_tracks
comparamos con el número real de pistas
comparison <- data.frame(num_tracks_JSON=num_real_pistas, num_tracks_csv= num_tracks )
comparison
por lo tanto los datos van acorde con este proyecto
Objetivo 1.-
##Extraer las características de los streaming de canciones y de sus
pistas como su nombre, artista, el número de pistas (en el caso del
Streaming) y la duración de la pista.
head(df_spotify,10)
head(new_df_tracks,10)
Objetivo 2.-
Hallar las pistas mas sonadas y los streamings más escuchados.
pistas_mas_sonadas <- left_join(new_df_tracks, df_tracks_uri, by="track_uri")
conteo <- pistas_mas_sonadas %>% count(track_uri)
pistas_mas_sonadas <- left_join(new_df_tracks, conteo, by="track_uri")
pistas_mas_sonadas <- arrange(pistas_mas_sonadas,desc(n))
pistas_mas_sonadas_top <- distinct(pistas_mas_sonadas,track_uri,.keep_all = TRUE)
pistas_mas_sonadas_top
##pistas_mas_sonadas <- arrange(pistas_mas_sonadas,desc(n))
##pistas_mas_sonadas_top <- filter(distinct(pistas_mas_sonadas,track_uri))
ahora guardaremos en un dataframe los 1000 mas escuchados y
desplegaremos los 10 mas escuchados
top_1000 <- head(pistas_mas_sonadas_top,1000)
top_10 <- head(pistas_mas_sonadas_top,10)
top_10
realizamos el grafico de audiencia del top 10
grafico <- ggplot(top_10, aes(x = track_name, y = n)) +
geom_bar(stat = "identity") + theme(axis.text.x = element_text(angle = 90, vjust = 0.5))
grafico

ahora veremos cual es el streaming mas escuchado, de base tendremos
el top de las 10 canciones mas escuchadas y el top de los streamings
dependerá del numero de holdouts y del numero de pistas que tenga
streamings_mas_pausados <- arrange(df_spotify,desc(num_holdouts))
streamings_mas_pausados
vemos cual es el mejor streaming
mejor_streaming <- df_spotify%>%
filter(indice == top_10$dataframe_id)
mejor_streaming
lista_pistas <- new_df_tracks%>%
filter(dataframe_id == 8)
lista_pistas
contiene una pista que esta en el top 10 , no contiene solo 5
pistas
Objetivo 3.-
Relacionar las características de cada canción con los resultados
para determinar que tienen en común.
jugaremos con el top 1000 de canciones, haciendo un grafico de
dispersión respecto al tiempo de duración de la canción con el top
relación_dpopularidad_duración_pista <- ggplot(top_1000, aes(x = n, y = duration_ms)) +
geom_point()
relación_dpopularidad_duración_pista

podemos concluir que las canciones mas escuchadas están en un rango
entre 2 minutos y 3 minutos, la mas escuchada está en el intervalo menor
a 2 minutos y medio
como conclusión final tenemos que para que una canción sea popular
su duración debe estar apegada al rango de entre 2 a 2 minutos y
medio
LS0tDQp0aXRsZTogIlIgTm90ZWJvb2siDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpUaGlzIGlzIGFuIFtSIE1hcmtkb3duXShodHRwOi8vcm1hcmtkb3duLnJzdHVkaW8uY29tKSBOb3RlYm9vay4gV2hlbiB5b3UgZXhlY3V0ZSBjb2RlIHdpdGhpbiB0aGUgbm90ZWJvb2ssIHRoZSByZXN1bHRzIGFwcGVhciBiZW5lYXRoIHRoZSBjb2RlLiANCg0KVHJ5IGV4ZWN1dGluZyB0aGlzIGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqUnVuKiBidXR0b24gd2l0aGluIHRoZSBjaHVuayBvciBieSBwbGFjaW5nIHlvdXIgY3Vyc29yIGluc2lkZSBpdCBhbmQgcHJlc3NpbmcgKkN0cmwrU2hpZnQrRW50ZXIqLiANCg0KYGBge3J9DQojI2luc3RhbGwucGFja2FnZXMoImRwbHlyIikNCiMjaW5zdGFsbC5wYWNrYWdlcygianNvbmxpdGUiKQ0KIyNpbnN0YWxsLnBhY2thZ2VzKCJyanNvbiIpDQojI2luc3RhbGwucGFja2FnZXMoImdncGxvdDIiKQ0KbGlicmFyeShjb25mbGljdGVkKQ0KbGlicmFyeShyanNvbikNCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KGpzb25saXRlKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGdncGxvdDIpDQpgYGANCg0KQWRkIGEgbmV3IGNodW5rIGJ5IGNsaWNraW5nIHRoZSAqSW5zZXJ0IENodW5rKiBidXR0b24gb24gdGhlIHRvb2xiYXIgb3IgYnkgcHJlc3NpbmcgKkN0cmwrQWx0K0kqLg0KDQpXaGVuIHlvdSBzYXZlIHRoZSBub3RlYm9vaywgYW4gSFRNTCBmaWxlIGNvbnRhaW5pbmcgdGhlIGNvZGUgYW5kIG91dHB1dCB3aWxsIGJlIHNhdmVkIGFsb25nc2lkZSBpdCAoY2xpY2sgdGhlICpQcmV2aWV3KiBidXR0b24gb3IgcHJlc3MgKkN0cmwrU2hpZnQrSyogdG8gcHJldmlldyB0aGUgSFRNTCBmaWxlKS4NCg0KVGhlIHByZXZpZXcgc2hvd3MgeW91IGEgcmVuZGVyZWQgSFRNTCBjb3B5IG9mIHRoZSBjb250ZW50cyBvZiB0aGUgZWRpdG9yLiBDb25zZXF1ZW50bHksIHVubGlrZSAqS25pdCosICpQcmV2aWV3KiBkb2VzIG5vdCBydW4gYW55IFIgY29kZSBjaHVua3MuIEluc3RlYWQsIHRoZSBvdXRwdXQgb2YgdGhlIGNodW5rIHdoZW4gaXQgd2FzIGxhc3QgcnVuIGluIHRoZSBlZGl0b3IgaXMgZGlzcGxheWVkLg0KDQojIHByb3llY3RvIHN0cmVhbSBleGl0b3NvIGVuIHNwb3RpZnkNCg0KIyBFbCBvYmpldGl2byBkZSBlc3RlIHByb3llY3RvIGVzIGFuYWxpemFyIG1lZGlhbnRlIGxvcyBkYXRvcyBwb3Igbml2ZWxlcyBkZSB1biBKU09OIHkgbG9zIGRhdG9zIGRlIGVudHJhZGEgZGUgdW4gQ1NWIHF1ZSBjb250aWVuZW4gbG9zIGlkIGRlIGxvcyBzdHJlYW1pbmcgeSBsYXMgcGlzdGFzIGVzY3VjaGFkYXMsIGN1YWwgZXMgZWwgZXN0cmVhbSB5IGxhIGNhbmNpw7NuIG1hcyBlc2N1Y2hhZGEgeSBvYnNlcnZhciBsYSByZWxhY2nDs24gZW50cmUgdW4gcmFuZ28gZGUgZHVyYWNpw7NuIGRlIGxhcyBtaXNtYXMgcGFyYSBkZXRlcm1pbmFyIGVudHJlIGxhcyBtZWpvcmVzIGNhbmNpb25lcyBzaSBoYXkgYWxndW5hIGluZmx1ZW5jaWEgZW4gbGEgZHVyYWNpw7NuIGRlIGxhIGNhbmNpw7NuIHBhcmEgc3Ugw6l4aXRvIHBhcmEgc2VyIHRlbmRlbmNpYS4NCg0KIyMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQojIyBDYXJnYW1vcyBlbCBwcmltZXIgZGF0YXNldA0KDQoNCiMjICMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCg0KDQojIyBwcmltZXJvIGxlZW1vcyBsYSBkYXRhIGRlc2RlIGVsIHByb3BpbyBKU09ODQpgYGB7cn0NCmRmIDwtIGZyb21KU09OKCJDOi9Vc2Vycy9FZGdhci9Eb2N1bWVudHMvR2l0SHViL0RhdGFNaW5pbmdfYW5kX01hY2hpbmVMZWFybmluZ19FZGdhclYvZGF0YS9Qcm95ZWN0bzEvY2hhbGxlbmdlX3NldC5qc29uIikNCmRmDQpgYGANCg0KIyMgUGFzYW1vcyBhIHVuIGRhdGEgZnJhbWUgbG9zIGR0b3MgbWFzIHJlbGV2YW50ZXMgcGFyYSBub3NvdHJvcyBxdWUgc2Vyw61hIGxhIFBsYXlsaXN0DQpgYGB7cn0NCmRmX3Nwb3RpZnkgPC0gZGYkcGxheWxpc3RzDQpkZl9zcG90aWZ5IDwtIGRmX3Nwb3RpZnklPiUNCiAgbXV0YXRlKGluZGljZSA9IHJvdy5uYW1lcyguKSkNCmRmX3Nwb3RpZnkNCmBgYA0KDQojIyBFeHBsb3JhbW9zIGxvcyBkYXRvcw0KYGBge3J9DQpkZl90cmFja3MgPC0gZGZfc3BvdGlmeSR0cmFja3MNCmhlYWQoZGZfdHJhY2tzKQ0KIyMgb2JzZXJ2YW1vcyBxdWUgcGFyYSBjYWRhIGxpc3RhIGRlIHBpc3RhcyBoYXkgdmFsb3JlcyBhc29jaWFkb3MgYSBjYWRhIHBpc3RhIGNvbW8gbm9tYnJlIGRlIGFydGlzdGEsIG5vbWJyZSBkZSBsYSBwaXN0YSB5IGR1cmFjaW9uDQpgYGANCg0KIyMgdmVyaWZpY2Ftb3Mgc2kgbmluZ3VuIGRhdG8gdGllbmUgZWxlbWVudG9zIE5BDQpgYGB7cn0NCg0KYW55KGlzLm5hKGRmX3RyYWNrcykpDQpgYGANCg0KIyMgIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIw0KDQojIyBDYXJnYW1vcyBlbCBzZWd1bmRvIGRhdGFzZXQNCg0KDQojIyAjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCg0KIyMgZWxpbWluYXJlbW9zIGNvbHVtbmFzIHF1ZSBubyBub3Mgc2lydmFuLCBwZXJvIGFudGVzIGRlYmVtb3MgYW5hbGl6YXIgZWwgZGF0YXNldCBkZSBsb3MgbnVtZXJvcyBkZSBzdHJlYW1pbmdzDQoNCmBgYHtyfQ0KZGZfZGF0YV9zcG90aWZ5IDwtIHJlYWQuY3N2KCJDOi9Vc2Vycy9FZGdhci9Eb2N1bWVudHMvR2l0SHViL0RhdGFNaW5pbmdfYW5kX01hY2hpbmVMZWFybmluZ19FZGdhclYvZGF0YS9Qcm95ZWN0bzEvc2FtcGxlX3N1Ym1pc3Npb24uY3N2IikNCg0KIyMgZGVmaW5pbW9zIGN1YWwgc2Vyw6EgbGEgcHJpbWVyYSBjb2x1bW5hDQoNCnByaW1lcmFfY29sdW1uYSA8LSBkZl9kYXRhX3Nwb3RpZnkkWDEwNDg1ODgNCiMjaGVhZChwcmltZXJhX2NvbHVtbmEsMTApDQoNCiMjIHRyYW5zZm9ybWFtb3MgbGFzIGZpbGFzIHJlc3RhbnRlcyBlbiBsaXN0YXMNCmxpc3Rhc19maWxhcyA8LSBsYXBwbHkoMTpucm93KGRmX2RhdGFfc3BvdGlmeSksZnVuY3Rpb24oaSkgYXMubGlzdCh0KGRmX2RhdGFfc3BvdGlmeVtpLC0xXSkpKQ0KDQojI2xpc3Rhc19maWxhcw0KZGZfdHJhY2tzX3VyaSA8LSBkYXRhLmZyYW1lKHRyYWNrc191cmkgPSB1bmxpc3QobGlzdGFzX2ZpbGFzKSkNCmhlYWQoZGZfdHJhY2tzX3VyaSwyKQ0KDQojIyBlc3RlIGNvZGlnbyBjb21iaW5hcmlhIGNhZGEgZWxlbWVudG8gY29uIHVuYSBsaXN0YSBkZSBlbGVtZW50b3MgcXVlIGNvbmZvcm1hbiBsYSBmaWxhDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMNCiMjZGZfdHJhY2tzX3VyaSA8LSBkYXRhLmZyYW1lKHRyYWNrc191cmkgPSBsaXN0YXNfZmlsYXMpDQoNCiMjY29tYmluYW1vcyBsYXMgY29sdW1uYXMgZGUgbG9zIHBpZCBjb24gbGFzIGxpc3Rhcw0KIyNkZl9kYXRhX3Nwb3RpZnlfY29tYmluYWRvIDwtIGRhdGEuZnJhbWUocGlkID0gcHJpbWVyYV9jb2x1bW5hLHRyYWNrc191cmkgPSBsaXN0YXNfZmlsYXMpDQojI2hlYWQoZGZfZGF0YV9zcG90aWZ5X2NvbWJpbmFkbywyKQ0KIyNoZWFkKGRmX2RhdGFfc3BvdGlmeV9jb21iaW5hZG8kdHJhY2tzX3VyaSwxKQ0KIyNoZWFkKGRmX2RhdGFfc3BvdGlmeV9jb21iaW5hZG8kdHJhY2tzX3VyaSwyKQ0KIyNkZl9kYXRhX3Nwb3RpZnlfY29tYmluYWRvIDwtIGFzLmRhdGEuZnJhbWUoZG8uY2FsbChyYmluZCwgbGlzdGFzX2NvbWJpbmFkYXMpKQ0KIyNoZWFkKGRmX2RhdGFfc3BvdGlmeV9jb21iaW5hZG8pDQojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjDQoNCiMjdGlwb19kZV9kYXRvIDwtIHNhcHBseShkZl9kYXRhX3Nwb3RpZnksIGNsYXNzKQ0KIyNkZl9kYXRhX3Nwb3RpZnlfdW5pZmljYWRhIDwtIHNwbGl0KGRmX2RhdGFfc3BvdGlmeSx0aXBvX2RlX2RhdG8pDQoNCmBgYA0KIyBleHBsb3JhbW9zIGRhdG9zIHBvciDDumx0aW1hIHZleiBhbnRlcyBkZSBpciBhIGxvIG51ZXN0cm8NCiMjIGRhdG9zIHBpZA0KYGBge3J9DQpwcmltZXJhX2NvbHVtbmEgPC0gZGZfZGF0YV9zcG90aWZ5JFgxMDQ4NTg4DQpkZl9waWQgPC0gZGF0YS5mcmFtZShwaWQgPSBwcmltZXJhX2NvbHVtbmEpDQpoZWFkKGRmX3BpZCwxMCkNCmBgYA0KDQojIyBkYXRvcyB0cmFja3NfdXJpDQpgYGB7cn0NCmRmX2RhdGFfc3BvdGlmeSA8LSByZWFkLmNzdigiQzovVXNlcnMvRWRnYXIvRG9jdW1lbnRzL0dpdEh1Yi9EYXRhTWluaW5nX2FuZF9NYWNoaW5lTGVhcm5pbmdfRWRnYXJWL2RhdGEvUHJveWVjdG8xL3NhbXBsZV9zdWJtaXNzaW9uLmNzdiIpDQoNCiMjIHRyYW5zZm9ybWFtb3MgbGFzIGZpbGFzIHJlc3RhbnRlcyBlbiBsaXN0YXMNCmxpc3Rhc19maWxhcyA8LSBsYXBwbHkoMTpucm93KGRmX2RhdGFfc3BvdGlmeSksZnVuY3Rpb24oaSkgYXMubGlzdCh0KGRmX2RhdGFfc3BvdGlmeVtpLC0xXSkpKQ0KDQojI2RhdGFmcmFtZSBkZSBsaXN0YXNfZmlsYXMNCmRmX3RyYWNrc191cmkgPC0gZGF0YS5mcmFtZSh0cmFja191cmkgPSB1bmxpc3QobGlzdGFzX2ZpbGFzKSkNCmhlYWQoZGZfdHJhY2tzX3VyaSwyKQ0KYGBgDQoNCg0KIyBleHBsb3JhbW9zIGRhdG9zIHBvciDDumx0aW1hIHZleiBhbnRlcyBkZSBpciBhIGxvIG51ZXN0cm8NCiMjIGRhdG9zIHRyYWNrX3VyaQ0KYGBge3J9DQpoZWFkKGRmX3RyYWNrc191cmksMTAwMCkNCmBgYA0KDQojIyB1bmEgdmV6IG9idGVuaWRvcyBsb3MgdmFsb3JlcyBxdWUgbmVjZXNpdGFtb3MgcHJvY2VkZW1vcyBhIGNvbnRhcmxvcw0KDQojIyBwcmltZXJvIGVtcGV6YXJlbW9zIGNvbiBsb3MgZGF0b3MgcGlkIHF1ZSBub3MgZGEgbGEgaW5mb3JtYWNpw7NuIGRlIGN1YW50b3Mgc3RyZWFtaW5ncyBodWJvIGVuIGVsIHByb2Nlc28gZGUgcmVjb2xlY2Npw7NuIGRlIGRhdG9zDQoNCmBgYHtyfQ0KZGZfbnVtZXJvX3N0cmVhbWluZ3MgPC0gZGZfcGlkJT4lDQogIHNlbGVjdChwaWQpJT4lDQogIGNvdW50KCkNCmRmX251bWVyb19zdHJlYW1pbmdzDQpwcmludCgib2pvIHF1ZSBoYXkgcXVlIGRlc2NvbnRhciAxMDAwIGRhdG9zIHF1ZSBlc3RhYmFuIHZhY2lvcyBhbCByZWFsaXphciBsYSBsaW1waWV6YSBkZSBsb3MgZGF0b3MgIikNCmBgYA0KDQoNCiMjI3JldmlzYW1vcyBzaSBoYXkgZGF0b3MgZHVwbGljYWRvcw0KYGBge3J9DQpkZl9udW1lcm9fc3RyZWFtaW5nc19kdXBsaWNhZG9zIDwtIGRmX3BpZCU+JQ0KICBmaWx0ZXIoZHVwbGljYXRlZChwaWQpKSU+JQ0KICBjb3VudCgpDQpkZl9udW1lcm9fc3RyZWFtaW5nc19kdXBsaWNhZG9zDQpgYGANCiMjIGNvbiBlc3RvIGNvbXByb2JhbW9zIHF1ZSBoYXkgMTAwMDAgZGF0b3MgZGUgc2VzacOzbiBkZSBzdHJlYW1pbmdzDQoNCiMjIGFob3JhIHZlcmlmaXF1ZW1vcyBzaSBoYXkgZGF0b3MgcmVwZXRpZG9zIGVuIGxhIGNvbHVtbmEgZGUgdHJhY2tzX3VyaSBxdWUgbm9zIG11ZXN0cmEgbGEgaW5mb3JtYWNpw7NuIGRlIGxhIHBpc3RhDQoNCmBgYHtyfQ0KZGZfbnVtZXJvX3RyYWNrc19yZXBldGlkb3MgPC0gZGZfdHJhY2tzX3VyaSU+JQ0KICBmaWx0ZXIoZHVwbGljYXRlZCh0cmFja3NfdXJpKSklPiUNCiAgY291bnQoKQ0KZGZfbnVtZXJvX3RyYWNrc19yZXBldGlkb3MNCmBgYA0KIyMgYWhvcmEgY29udGFtb3MgbG9zIGRhdG9zIHRvdGFsZXMgZGUgbGFzIHBpc3RhbA0KYGBge3J9DQpkZl9udW1lcm9fdG90YWxfdHJhY2tzIDwtIGRmX3RyYWNrc191cmklPiUNCiAgc2VsZWN0KHRyYWNrc191cmkpJT4lDQogIGNvdW50KCkNCmRmX251bWVyb190b3RhbF90cmFja3MNCmBgYA0KIyMgcmVhbGl6YW1vcyBsYSBkaWZlcmVuY2lhIHBhcmEgY29udGFiaWxpemFyIGVsIG51bWVybyByZWFsIGRlIHBpc3Rhcw0KYGBge3J9DQpudW1fcmVhbF9waXN0YXMgPC0gZGZfbnVtZXJvX3RvdGFsX3RyYWNrcyAtIGRmX251bWVyb190cmFja3NfcmVwZXRpZG9zDQpudW1fcmVhbF9waXN0YXMNCmBgYA0KDQojIyBhaG9yYSBjb250YW1vcyBsb3Mgc3RyZWFtaW5ncyBxdWUgdGllbmUgZWwgb3RybyBkYXRhc2V0DQoNCmBgYHtyfQ0KDQpudW1fc3RyZWFtaW5ncyA8LSBkZl9zcG90aWZ5JT4lDQogIHNlbGVjdChwaWQpJT4lDQogIGNvdW50KCkNCm51bV9zdHJlYW1pbmdzDQoNCmBgYA0KIyMjIyBwb3IgbG8gdmlzdG8gZWwgbsO6bWVybyBkZSBzdHJlYW1pbmdzIGNvaW5jaWRlbiBjb24gbG9zIGRhdG9zIGRlbCBkYXRhc2V0IGRlIGxhcyBwaXN0YXMNCg0KIyMgYWhvcmEgY29udGFtb3MgbG9zIGRhdG9zIGRlIGxhcyBwaXN0YXMgZGVsIGRhdGFzZXQgY2hhbGxlbmdlDQoNCiMjIHByaW1lcm8gdW5pbW9zIGxvcyBkYXRhZnJhbWVzIGVuIHVubyBzb2xvDQoNCmBgYHtyfQ0KbmV3X2RmX3RyYWNrcyA8LSBiaW5kX3Jvd3MoZGZfdHJhY2tzLCAuaWQgPSAiZGF0YWZyYW1lX2lkIikNCm5ld19kZl90cmFja3MNCmBgYA0KDQojIyBhaG9yYSBjb250YW1vcyBlbCBudW1lcm8gZGUgcGlzdGFzIHF1ZSB0aWVuZSBlc3RlIGRhdGFzZXQNCg0KYGBge3J9DQpudW1fdHJhY2tzIDwtIG5ld19kZl90cmFja3MlPiUNCiAgc2VsZWN0KHRyYWNrX3VyaSklPiUNCiAgY291bnQoKQ0KbnVtX3RyYWNrcw0KYGBgDQojIyByZXZpc2Ftb3Mgc2kgbm8gaGF5IHJlcGV0aWRvcw0KDQpgYGB7cn0NCm51bV90cmFja3MgPC0gbmV3X2RmX3RyYWNrcyU+JQ0KICBkaXN0aW5jdCh0cmFja191cmkpJT4lDQogIGNvdW50KCkNCm51bV90cmFja3MNCmBgYA0KIyMgY29tcGFyYW1vcyBjb24gZWwgbsO6bWVybyByZWFsIGRlIHBpc3Rhcw0KDQpgYGB7cn0NCmNvbXBhcmlzb24gPC0gZGF0YS5mcmFtZShudW1fdHJhY2tzX0pTT049bnVtX3JlYWxfcGlzdGFzLCBudW1fdHJhY2tzX2Nzdj0gbnVtX3RyYWNrcyApDQpjb21wYXJpc29uDQpgYGANCiMjIHBvciBsbyB0YW50byBsb3MgZGF0b3MgdmFuIGFjb3JkZSBjb24gZXN0ZSBwcm95ZWN0bw0KDQojIE9iamV0aXZvIDEuLQ0KIyNFeHRyYWVyIGxhcyBjYXJhY3RlcsOtc3RpY2FzIGRlIGxvcyBzdHJlYW1pbmcgZGUgY2FuY2lvbmVzIHkgZGUgc3VzIHBpc3RhcyBjb21vIHN1IG5vbWJyZSwgYXJ0aXN0YSwgZWwgbsO6bWVybyBkZSBwaXN0YXMgKGVuIGVsIGNhc28gZGVsIFN0cmVhbWluZykgeSBsYSBkdXJhY2nDs24gZGUgbGEgcGlzdGEuDQoNCmBgYHtyfQ0KaGVhZChkZl9zcG90aWZ5LDEwKQ0KaGVhZChuZXdfZGZfdHJhY2tzLDEwKQ0KYGBgDQoNCiMgT2JqZXRpdm8gMi4tDQoNCiMjIEhhbGxhciBsYXMgcGlzdGFzIG1hcyBzb25hZGFzIHkgbG9zIHN0cmVhbWluZ3MgbcOhcyBlc2N1Y2hhZG9zLg0KDQpgYGB7cn0NCnBpc3Rhc19tYXNfc29uYWRhcyA8LSBsZWZ0X2pvaW4obmV3X2RmX3RyYWNrcywgZGZfdHJhY2tzX3VyaSwgYnk9InRyYWNrX3VyaSIpDQpjb250ZW8gPC0gcGlzdGFzX21hc19zb25hZGFzICU+JSBjb3VudCh0cmFja191cmkpDQpwaXN0YXNfbWFzX3NvbmFkYXMgPC0gbGVmdF9qb2luKG5ld19kZl90cmFja3MsIGNvbnRlbywgYnk9InRyYWNrX3VyaSIpDQpwaXN0YXNfbWFzX3NvbmFkYXMgPC0gYXJyYW5nZShwaXN0YXNfbWFzX3NvbmFkYXMsZGVzYyhuKSkNCnBpc3Rhc19tYXNfc29uYWRhc190b3AgPC0gZGlzdGluY3QocGlzdGFzX21hc19zb25hZGFzLHRyYWNrX3VyaSwua2VlcF9hbGwgPSBUUlVFKQ0KcGlzdGFzX21hc19zb25hZGFzX3RvcA0KYGBgDQoNCiMjIGFob3JhIGd1YXJkYXJlbW9zIGVuIHVuIGRhdGFmcmFtZSBsb3MgMTAwMCBtYXMgZXNjdWNoYWRvcyB5IGRlc3BsZWdhcmVtb3MgbG9zIDEwIG1hcyBlc2N1Y2hhZG9zDQoNCmBgYHtyfQ0KDQp0b3BfMTAwMCA8LSBoZWFkKHBpc3Rhc19tYXNfc29uYWRhc190b3AsMTAwMCkNCnRvcF8xMCA8LSBoZWFkKHBpc3Rhc19tYXNfc29uYWRhc190b3AsMTApDQp0b3BfMTANCmBgYA0KDQojIyByZWFsaXphbW9zIGVsIGdyYWZpY28gZGUgYXVkaWVuY2lhIGRlbCB0b3AgMTANCg0KYGBge3J9DQoNCmdyYWZpY28gPC0gZ2dwbG90KHRvcF8xMCwgYWVzKHggPSB0cmFja19uYW1lLCB5ID0gbikpICsNCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUpKQ0KZ3JhZmljbw0KYGBgDQoNCiMjIGFob3JhIHZlcmVtb3MgY3VhbCBlcyBlbCBzdHJlYW1pbmcgbWFzIGVzY3VjaGFkbywgZGUgYmFzZSB0ZW5kcmVtb3MgZWwgdG9wIGRlIGxhcyAxMCBjYW5jaW9uZXMgbWFzIGVzY3VjaGFkYXMgeSBlbCB0b3AgZGUgbG9zIHN0cmVhbWluZ3MgZGVwZW5kZXLDoSBkZWwgbnVtZXJvIGRlIGhvbGRvdXRzIHkgZGVsIG51bWVybyBkZSBwaXN0YXMgcXVlIHRlbmdhDQoNCmBgYHtyfQ0Kc3RyZWFtaW5nc19tYXNfcGF1c2Fkb3MgPC0gYXJyYW5nZShkZl9zcG90aWZ5LGRlc2MobnVtX2hvbGRvdXRzKSkNCnN0cmVhbWluZ3NfbWFzX3BhdXNhZG9zDQpgYGANCiMjIHZlbW9zIGN1YWwgZXMgZWwgbWVqb3Igc3RyZWFtaW5nDQpgYGB7cn0NCm1lam9yX3N0cmVhbWluZyA8LSBkZl9zcG90aWZ5JT4lDQogIGZpbHRlcihpbmRpY2UgPT0gdG9wXzEwJGRhdGFmcmFtZV9pZCkNCm1lam9yX3N0cmVhbWluZw0KDQpsaXN0YV9waXN0YXMgPC0gbmV3X2RmX3RyYWNrcyU+JQ0KICBmaWx0ZXIoZGF0YWZyYW1lX2lkID09IDgpDQpsaXN0YV9waXN0YXMNCmBgYA0KIyMgY29udGllbmUgdW5hIHBpc3RhIHF1ZSBlc3RhIGVuIGVsIHRvcCAxMCAsIG5vIGNvbnRpZW5lIHNvbG8gNSBwaXN0YXMgDQoNCiMgT2JqZXRpdm8gMy4tDQoNCiMjIFJlbGFjaW9uYXIgbGFzIGNhcmFjdGVyw61zdGljYXMgZGUgY2FkYSBjYW5jacOzbiBjb24gbG9zIHJlc3VsdGFkb3MgcGFyYSBkZXRlcm1pbmFyIHF1ZSB0aWVuZW4gZW4gY29tw7puLg0KDQojIyMganVnYXJlbW9zIGNvbiBlbCB0b3AgMTAwMCBkZSBjYW5jaW9uZXMsIGhhY2llbmRvIHVuIGdyYWZpY28gZGUgZGlzcGVyc2nDs24gcmVzcGVjdG8gYWwgdGllbXBvIGRlIGR1cmFjacOzbiBkZSBsYSBjYW5jacOzbiBjb24gZWwgdG9wDQoNCmBgYHtyfQ0KcmVsYWNpw7NuX2Rwb3B1bGFyaWRhZF9kdXJhY2nDs25fcGlzdGEgPC0gZ2dwbG90KHRvcF8xMDAwLCBhZXMoeCA9IG4sIHkgPSBkdXJhdGlvbl9tcykpICsNCiAgZ2VvbV9wb2ludCgpDQpyZWxhY2nDs25fZHBvcHVsYXJpZGFkX2R1cmFjacOzbl9waXN0YQ0KYGBgDQojIyBwb2RlbW9zIGNvbmNsdWlyIHF1ZSBsYXMgY2FuY2lvbmVzIG1hcyBlc2N1Y2hhZGFzIGVzdMOhbiBlbiB1biByYW5nbyBlbnRyZSAyIG1pbnV0b3MgeSAzIG1pbnV0b3MsIGxhIG1hcyBlc2N1Y2hhZGEgZXN0w6EgZW4gZWwgaW50ZXJ2YWxvIG1lbm9yIGEgMiBtaW51dG9zIHkgbWVkaW8NCg0KIyMgY29tbyBjb25jbHVzacOzbiBmaW5hbCB0ZW5lbW9zIHF1ZSBwYXJhIHF1ZSB1bmEgY2FuY2nDs24gc2VhIHBvcHVsYXIgc3UgZHVyYWNpw7NuIGRlYmUgZXN0YXIgYXBlZ2FkYSBhbCByYW5nbyBkZSBlbnRyZSAyIGEgMiBtaW51dG9zIHkgbWVkaW8NCg0KDQoNCg0K